﻿Imports System.Threading
Imports System.Configuration
Imports System.IO

Public Class Cls_Task

#Region " Variables Protegidas "
    Protected m_DLL As String
    Protected m_Clase As String
    Protected m_Metodo As String
    Protected m_IdTarea As Integer
    Protected m_NombreTarea As String
    Protected m_SubjectError As String
    Protected m_SubjectOK As String
    Protected m_EmailOrigen As String
    Protected m_ListaEmail As String
    Protected m_FechaTarea As Integer
    Protected m_HoraTarea As String
    Protected m_DiaTarea As Integer
    Protected m_Horas As String
    Protected m_TipoAgendamiento As enumTipoAgendamiento
#End Region

#Region " Enumeraciones "
    Public Enum enumTipoAgendamiento
        DiaSemana = 1
        DiaMes = 2
        Fecha = 3
        Hora = 4
    End Enum
#End Region

#Region " Propiedades "
    Public Property TipoAgendamiento() As enumTipoAgendamiento
        Get
            Return m_TipoAgendamiento
        End Get
        Set(ByVal value As enumTipoAgendamiento)
            m_TipoAgendamiento = value
        End Set
    End Property

    Public Property Horas() As String
        Get
            Return m_Horas
        End Get
        Set(ByVal value As String)
            m_Horas = value
        End Set
    End Property

    Public Property HoraTarea() As String
        Get
            Return m_HoraTarea
        End Get
        Set(ByVal value As String)
            m_HoraTarea = value
        End Set
    End Property

    Public Property FechaTarea() As Integer
        Get
            Return m_FechaTarea
        End Get
        Set(ByVal value As Integer)
            m_FechaTarea = value
        End Set
    End Property

    Public Property DiaTarea() As Integer
        Get
            Return m_DiaTarea
        End Get
        Set(ByVal value As Integer)
            m_DiaTarea = value
        End Set
    End Property

    Public Property EmailOrigen() As String
        Get
            Return m_EmailOrigen
        End Get
        Set(ByVal value As String)
            m_EmailOrigen = value
        End Set
    End Property

    Public Property ListaEmail() As String
        Get
            Return m_ListaEmail
        End Get
        Set(ByVal value As String)
            m_ListaEmail = value
        End Set
    End Property

    Public Property IdTarea() As Integer
        Get
            Return m_IdTarea
        End Get
        Set(ByVal value As Integer)
            m_IdTarea = value
        End Set
    End Property

    Public Property NombreTarea() As String
        Get
            Return m_NombreTarea
        End Get
        Set(ByVal value As String)
            m_NombreTarea = value
        End Set
    End Property

    Public Property DLL() As String
        Get
            Return m_DLL
        End Get
        Set(ByVal value As String)
            m_DLL = value
        End Set
    End Property

    Public Property Clase() As String
        Get
            Return m_Clase
        End Get
        Set(ByVal value As String)
            m_Clase = value
        End Set
    End Property

    Public Property Metodo() As String
        Get
            Return m_Metodo
        End Get
        Set(ByVal value As String)
            m_Metodo = value
        End Set
    End Property

    Public Property SubjectError() As String
        Get
            Return m_SubjectError
        End Get
        Set(ByVal value As String)
            m_SubjectError = value
        End Set
    End Property

    Public Property SubjectOK() As String
        Get
            Return m_SubjectOK
        End Get
        Set(ByVal value As String)
            m_SubjectOK = value
        End Set
    End Property
#End Region

#Region " Constructor de la Clase "
#End Region

#Region " Métodos Privados "
    Public Function InvokeTask( _
        ByVal TASK_ID As Integer, _
        ByVal NOMBRE As String, _
        ByVal HORA_INICIO As String, _
        ByVal N_HORA As String, _
        ByVal N_DIA As String, _
        ByVal DLL As String, _
        ByVal CLASE As String, _
        ByVal METODO As String, _
        ByVal S_SUBJECT_ERROR As String, _
        ByVal S_SUBJECT_OK As String, _
        ByVal S_EMAIL_ORIGEN As String, _
        ByVal S_RUTA_RESPALDO As String, _
        ByVal S_LISTA_EMAIL As String)

        Dim Exec As New DotNetDAL.SQLPersistence(True, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()
        rp.StoredProcedure = "SP_TASK_GET_TAREA"
        rp.AddParametro(TASK_ID)
        Exec.ExecuteScalar(rp)


        If rp.GetScalar = "1" Then
            Exec.Rollback()
            Return "1"
        End If

        Exec.Commit()

        m_IdTarea = TASK_ID
        UpdateEstadoTarea(1) 'Actualizar estado de la tarea a 1


        Dim mThreadFic As Thread
        ' Creamos una variable de la clase en la que está el Sub que se usará en el Thread

        Dim mProcesarFic As New Cls_Task
        mProcesarFic.IdTarea = TASK_ID
        mProcesarFic.NombreTarea = NOMBRE
        mProcesarFic.HoraTarea = HORA_INICIO
        mProcesarFic.Horas = N_HORA
        mProcesarFic.DiaTarea = N_DIA
        mProcesarFic.DLL = DLL
        mProcesarFic.Clase = CLASE
        mProcesarFic.Metodo = METODO
        mProcesarFic.SubjectError = S_SUBJECT_ERROR
        mProcesarFic.SubjectOK = S_SUBJECT_OK
        mProcesarFic.EmailOrigen = S_EMAIL_ORIGEN
        mProcesarFic.ListaEmail = S_LISTA_EMAIL
        mProcesarFic.FechaTarea = Format(Now, "yyyyMMdd")

        ' Asignamos el Sub que queremos usar al crear una nueva instancia de la clase del tipo Thread
        mThreadFic = New Thread(New ThreadStart(AddressOf mProcesarFic.Invoke))
        mThreadFic.IsBackground = True
        mThreadFic.Priority = ThreadPriority.Normal

        ' Para que se ejecute el Thread, hay que indicarselo de forma explícita
        mThreadFic.Start()

        Return 0
    End Function

    Public Sub GetTasks()
        GetTasks_Hora()

        GetTasks_DiaMes()

        GetTasks_DiaSemana()

        GetTasks_Fecha()
    End Sub

    Public Sub GetTasks_Hora()
        Dim Exec As New DotNetDAL.SQLPersistence(False, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()

        rp.StoredProcedure = "SP_TASK_GET_AGENDAMIENTO_HORA"
        Exec.ExecuteDatatable(rp)
        Exec.Dispose()

        'Ejecutar los metodos
        If rp.TieneDatos Then
            For Each dr As DataRow In rp.DtTable.Rows
                ' Creamos una variable de la clase en la que está el Sub que se usará en el Thread
                Dim mProcesarFic As Cls_Task = New Cls_Task

                mProcesarFic.IdTarea = dr("TASK_ID")
                mProcesarFic.NombreTarea = dr("NOMBRE")
                mProcesarFic.HoraTarea = dr("HORA_INICIO")
                mProcesarFic.Horas = dr("N_HORA")
                mProcesarFic.DiaTarea = dr("N_DIA")
                mProcesarFic.DLL = dr("DLL")
                mProcesarFic.Clase = dr("CLASE")
                mProcesarFic.Metodo = dr("METODO")
                mProcesarFic.SubjectError = dr("S_SUBJECT_ERROR")
                mProcesarFic.SubjectOK = dr("S_SUBJECT_OK")
                mProcesarFic.EmailOrigen = dr("S_EMAIL_ORIGEN")
                mProcesarFic.ListaEmail = dr("S_LISTA_EMAIL")
                mProcesarFic.FechaTarea = Format(Now, "yyyyMMdd")
                mProcesarFic.TipoAgendamiento = enumTipoAgendamiento.Hora

                Dim mThreadFic As Thread

                ' Asignamos el Sub que queremos usar al crear una nueva instancia de la clase del tipo Thread
                mThreadFic = New Thread(New ThreadStart(AddressOf mProcesarFic.Invoke))
                mThreadFic.IsBackground = True
                mThreadFic.Priority = ThreadPriority.Normal

                ' Para que se ejecute el Thread, hay que indicarselo de forma explícita
                mThreadFic.Start()
            Next
        End If
    End Sub

    Public Sub GetTasks_DiaMes()
        Dim Exec As New DotNetDAL.SQLPersistence(False, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()

        rp.StoredProcedure = "SP_TASK_GET_AGENDAMIENTO_DIA_MES"
        Exec.ExecuteDatatable(rp)
        Exec.Dispose()

        'Ejecutar los metodos
        If rp.TieneDatos Then
            For Each dr As DataRow In rp.DtTable.Rows
                Dim mThreadFic As Thread

                ' Creamos una variable de la clase en la que está el Sub que se usará en el Thread
                Dim mProcesarFic As Cls_Task = New Cls_Task

                mProcesarFic.IdTarea = dr("TASK_ID")
                mProcesarFic.NombreTarea = dr("NOMBRE")
                mProcesarFic.HoraTarea = dr("HORA_INICIO")
                mProcesarFic.Horas = dr("N_HORA")
                mProcesarFic.DiaTarea = dr("N_DIA")
                mProcesarFic.DLL = dr("DLL")
                mProcesarFic.Clase = dr("CLASE")
                mProcesarFic.Metodo = dr("METODO")
                mProcesarFic.SubjectError = dr("S_SUBJECT_ERROR")
                mProcesarFic.SubjectOK = dr("S_SUBJECT_OK")
                mProcesarFic.EmailOrigen = dr("S_EMAIL_ORIGEN")
                mProcesarFic.ListaEmail = dr("S_LISTA_EMAIL")
                mProcesarFic.FechaTarea = Format(Now, "yyyyMMdd")
                mProcesarFic.TipoAgendamiento = enumTipoAgendamiento.DiaMes

                mProcesarFic.Invoke()
                '' Asignamos el Sub que queremos usar al crear una nueva instancia de la clase del tipo Thread
                'mThreadFic = New Thread(New ThreadStart(AddressOf mProcesarFic.Invoke))
                'mThreadFic.IsBackground = True
                'mThreadFic.Priority = ThreadPriority.Normal

                '' Para que se ejecute el Thread, hay que indicarselo de forma explícita
                'mThreadFic.Start()
            Next
        End If
    End Sub

    Public Sub GetTasks_DiaSemana()
        Dim Exec As New DotNetDAL.SQLPersistence(False, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()
        rp.StoredProcedure = "SP_TASK_GET_AGENDAMIENTO_DIA_SEMANA"
        rp.AddParametro(Now.DayOfWeek)
        Exec.ExecuteDatatable(rp)
        Exec.Dispose()

        'Ejecutar los metodos
        If rp.TieneDatos Then
            For Each dr As DataRow In rp.DtTable.Rows
                Dim mThreadFic As Thread

                ' Creamos una variable de la clase en la que está el Sub que se usará en el Thread
                Dim mProcesarFic As Cls_Task = New Cls_Task

                mProcesarFic.IdTarea = dr("TASK_ID")
                mProcesarFic.NombreTarea = dr("NOMBRE")
                mProcesarFic.HoraTarea = dr("HORA_INICIO")
                mProcesarFic.Horas = dr("N_HORA")
                mProcesarFic.DiaTarea = dr("N_DIA")
                mProcesarFic.DLL = dr("DLL")
                mProcesarFic.Clase = dr("CLASE")
                mProcesarFic.Metodo = dr("METODO")
                mProcesarFic.SubjectError = dr("S_SUBJECT_ERROR")
                mProcesarFic.SubjectOK = dr("S_SUBJECT_OK")
                mProcesarFic.EmailOrigen = dr("S_EMAIL_ORIGEN")
                mProcesarFic.ListaEmail = dr("S_LISTA_EMAIL")
                mProcesarFic.FechaTarea = Format(Now, "yyyyMMdd")
                mProcesarFic.TipoAgendamiento = enumTipoAgendamiento.DiaSemana

                ' Asignamos el Sub que queremos usar al crear una nueva instancia de la clase del tipo Thread
                mThreadFic = New Thread(New ThreadStart(AddressOf mProcesarFic.Invoke))
                mThreadFic.IsBackground = True
                mThreadFic.Priority = ThreadPriority.Normal

                ' Para que se ejecute el Thread, hay que indicarselo de forma explícita
                mThreadFic.Start()
            Next
        End If
    End Sub

    Public Sub GetTasks_Fecha()
        Dim Exec As New DotNetDAL.SQLPersistence(False, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()
        rp.StoredProcedure = "SP_TASK_GET_AGENDAMIENTO_FECHA"
        Exec.ExecuteDatatable(rp)
        Exec.Dispose()

        'Ejecutar los metodos
        If rp.TieneDatos Then
            For Each dr As DataRow In rp.DtTable.Rows
                ' Creamos una variable de la clase en la que está el Sub que se usará en el Thread
                Dim mProcesarFic As Cls_Task = New Cls_Task

                mProcesarFic.IdTarea = dr("TASK_ID")
                mProcesarFic.NombreTarea = dr("NOMBRE")
                mProcesarFic.HoraTarea = dr("HORA_INICIO")
                mProcesarFic.Horas = dr("N_HORA")
                mProcesarFic.DiaTarea = dr("N_DIA")
                mProcesarFic.DLL = dr("DLL")
                mProcesarFic.Clase = dr("CLASE")
                mProcesarFic.Metodo = dr("METODO")
                mProcesarFic.SubjectError = dr("S_SUBJECT_ERROR")
                mProcesarFic.SubjectOK = dr("S_SUBJECT_OK")
                mProcesarFic.EmailOrigen = dr("S_EMAIL_ORIGEN")
                mProcesarFic.ListaEmail = dr("S_LISTA_EMAIL")
                mProcesarFic.FechaTarea = Format(Now, "yyyyMMdd")
                mProcesarFic.TipoAgendamiento = enumTipoAgendamiento.Fecha

                Dim mThreadFic As Thread

                mThreadFic = New Thread(New ThreadStart(AddressOf mProcesarFic.Invoke))
                mThreadFic.IsBackground = True
                mThreadFic.Priority = ThreadPriority.Normal
                mThreadFic.Start()
            Next
        End If
    End Sub

    Private Sub Invoke()
        Try
            Dim rp As New DotNetResponse.SQLPersistence
            Dim a As System.Reflection.Assembly
            Dim FechaIniEjec As Integer
            Dim HoraIniEjec As String
            Dim FechaFinEjec As Integer
            Dim HoraFinEjec As String
            Dim Param(1) As Object
            Dim oClass As Type
            Dim ob

            UpdateEstadoTarea(1) 'Actualizar estado de la tarea a 1

            Param(0) = rp
            Param(1) = m_IdTarea

            If Not File.Exists(AppDomain.CurrentDomain.BaseDirectory & m_DLL.Trim & ".dll") Then
                Throw New Exception("No existe libreria asociada a la tarea")
            End If

            a = System.Reflection.Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory & m_DLL & ".dll")
            oClass = a.GetType(m_DLL & "." & Clase)
            ob = a.CreateInstance(m_DLL & "." & Clase)

            FechaIniEjec = Format(Now, "yyyyMMdd")
            HoraIniEjec = Format(Now, "hh:mm")

            oClass.GetMethod(Metodo).Invoke(ob, Param)

            FechaFinEjec = Format(Now, "yyyyMMdd")
            HoraFinEjec = Format(Now, "hh:mm")

            If Not rp.PErrores Is Nothing Then
                If rp.PErrores.Length > 0 Then
                    Dim sDescError As String = "Se han encontrado error(es) en la ejecución de la tarea '" & m_NombreTarea & "':" & vbNewLine

                    For Each sError As String In rp.PErrores
                        sDescError = sError & vbNewLine
                    Next

                    SendMail(m_ListaEmail, m_SubjectError, sDescError, m_EmailOrigen)

                    UpdateHistorialTarea(m_IdTarea, m_FechaTarea, m_HoraTarea, FechaIniEjec, HoraIniEjec, FechaFinEjec, HoraFinEjec, "ER", sDescError)
                End If
            Else
                If m_SubjectOK.Trim.Length > 0 Then
                    SendMail(m_ListaEmail, m_SubjectOK, "Ejecución OK", m_EmailOrigen)
                End If

                UpdateHistorialTarea(m_IdTarea, m_FechaTarea, m_HoraTarea, FechaIniEjec, HoraIniEjec, FechaFinEjec, HoraFinEjec, "OK", "Ejecución exitosa")
            End If

            'Actualiza el estado de la tarea ([TBL_TASK])
            UpdateEstadoTarea(0)

            'Inserta en la tabla de historico correspondiente al agendamiento
            InsertaHistoricoTarea()
        Catch ex As Exception
            UpdateEstadoTarea(0)

            SendMail(m_ListaEmail, m_SubjectError, "Se ha generado la siguiente excepción en la tarea '" & m_NombreTarea & "': " & ex.Message, m_EmailOrigen)
        End Try
    End Sub

    Private Sub UpdateEstadoTarea(ByVal Estado As String)
        UpdateEstadoTarea(m_IdTarea, Estado)
    End Sub

    Public Shared Sub UpdateEstadoTarea(ByVal EstaTarea As Integer, ByVal Estado As Integer)
        Dim exec As New DotNetDAL.SQLPersistence(True, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()

        rp.StoredProcedure = "SP_TASK_SAVE_ESTADO"

        rp.AddParametro(EstaTarea)
        rp.AddParametro(Estado)

        exec.ExecuteScalar(rp)

        exec.Commit()
    End Sub

    Private Sub UpdateHistorialTarea(ByVal IdTarea As Integer, ByVal FechaEjecutar As Integer, ByVal HoraEjecutar As String, ByVal FechaInicio As Integer, ByVal HoraInicio As String, ByVal FechaFin As Integer, ByVal HoraFin As String, ByVal Estado As String, ByVal DescError As String)
        Dim exec As New DotNetDAL.SQLPersistence(True, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()

        rp.StoredProcedure = "SP_TASK_INS_HISTORIAL"

        rp.AddParametro(IdTarea)
        rp.AddParametro(FechaEjecutar)
        rp.AddParametro(HoraEjecutar)
        rp.AddParametro(FechaInicio)
        rp.AddParametro(HoraInicio)
        rp.AddParametro(FechaFin)
        rp.AddParametro(HoraFin)
        rp.AddParametro(Estado)
        rp.AddParametro(DescError)

        exec.ExecuteNonQuery(rp)

        exec.Commit()
    End Sub

    Private Sub InsertaHistoricoTarea()
        Dim exec As New DotNetDAL.SQLPersistence(True, "cnn")
        Dim rp As New DotNetResponse.SQLPersistence()

        Select Case m_TipoAgendamiento
            Case enumTipoAgendamiento.DiaMes
                rp.StoredProcedure = "SP_TASK_INS_DIA_MES_HIST"
                rp.AddParametro(m_IdTarea)
            Case enumTipoAgendamiento.DiaSemana
                rp.StoredProcedure = "SP_TASK_INS_DIA_SEMANA_HIST"
                rp.AddParametro(m_IdTarea)
                rp.AddParametro(m_HoraTarea)
            Case enumTipoAgendamiento.Fecha
                rp.StoredProcedure = "SP_TASK_INS_FECHA_HIST"
                rp.AddParametro(m_IdTarea)
                rp.AddParametro(m_HoraTarea)
            Case enumTipoAgendamiento.Hora
                rp.StoredProcedure = "SP_TASK_INS_HORA_HIST"
                rp.AddParametro(m_IdTarea)
                rp.AddParametro(m_HoraTarea)
        End Select

        exec.ExecuteNonQuery(rp)

        exec.Commit()
    End Sub

    Protected Sub LogFile(ByVal mensaje As String)
        Dim archivoLog As String = ConfigurationManager.AppSettings("ArchivoLog").Replace("[Fecha]", Now.ToString("yyyymmdd"))

        Dim fs As New FileStream(archivoLog, FileMode.OpenOrCreate, FileAccess.Write)
        Dim m_streamWriter As New StreamWriter(fs)
        m_streamWriter.BaseStream.Seek(0, SeekOrigin.End)
        m_streamWriter.WriteLine(mensaje)
        m_streamWriter.Flush()
        m_streamWriter.Close()
    End Sub
#End Region

#Region " Funciones "
    Public Shared Function IsMail(ByVal p_email As String) As Boolean
        Dim l_reg As New System.Text.RegularExpressions.Regex("^(([^<;>;()[\]\\.,;:\s@\""]+" & _
        "(\.[^<;>;()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@" & _
        "((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" & _
        "\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+" & _
        "[a-zA-Z]{2,}))$")
        Return (l_reg.IsMatch(p_email))
    End Function

    Private Function SendMail(ByVal to_ As String, ByVal subject As String, ByVal body As String, ByVal From As String) As String
        Dim Retorno As Boolean = False

        Try
            Dim sevidor As String = ConfigurationManager.AppSettings("MAIL_SRVMAIL")
            Dim user_mail As String = ConfigurationManager.AppSettings("MAIL_USUARIO")
            Dim clave_mail As String = ConfigurationManager.AppSettings("MAIL_CLAVE")

            Dim mail As New System.Net.Mail.MailMessage(From, to_.Replace(";", ","), subject, body)
            mail.IsBodyHtml = True
            Dim smtp As New System.Net.Mail.SmtpClient(sevidor)

            smtp.Credentials = New System.Net.NetworkCredential(user_mail, clave_mail)
            smtp.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network
            smtp.Send(mail)

            Retorno = True
        Catch ex As Exception

        End Try

        Return Retorno
    End Function
#End Region
End Class
